//Cyclone-Portal
//GAM 450 Final Project
//Gregory Dillon, Brian Gates, Kyle Chmielewski
//ParticleSystem.cpp
//creates the particles and connects them to each other
#include "ParticleSystem.h"
#include "qec.h"

//static defines for particles and their connection
#define ROD_COUNT 1
#define BASE_MASS 1
#define EXTRA_MASS 1
#define RADIUS    0.5

//
//ParticleSystem constructor
ParticleSystem::ParticleSystem(void)
{
   // Create the masses and connections.
   //set particle variables
   for (unsigned i = 0; i < 2; i++)
   {
      unsigned x = (i%12)/2;
      particleArray[i].setPosition(
         0, 5, 10+3*i);
      particleArray[i].setVelocity(0,0,-0.02);
      particleArray[i].setDamping(0.9f);
      particleArray[i].setAcceleration(cyclone::Vector3::GRAVITY);
      particleArray[i].clearAccumulator();
   }  // for

   //create a rod
   rods = new ParticleRod[ROD_COUNT];

   //connect the particles to the rod
   for (unsigned i = 0; i < ROD_COUNT; i++)
   {
      //length of the rod
      real length;

      //attach particle pointers to the rod array
      rods[i].particle[0] = &particleArray[i];
      rods[i].particle[1] = &particleArray[i + 1];
      
      //set length of rod
      length = (rods[i].particle[0]->getPosition()-rods[i].particle[1]->getPosition()).magnitude();
         
      rods[i].length = length;
   }  // for
}  // particleSystem constructor


//
//ParticleSystem::update()
//updates the position of the particle system
void ParticleSystem::update()
{
   //update positions of particles attached to the system
    particleArray[0].setPosition(particleArray[0].getPosition()+particleArray[0].getVelocity());
    particleArray[1].setPosition(particleArray[1].getPosition()+particleArray[1].getVelocity());

}  //ParticleSystem::update()

//
//ParticleSystem::updateAdditionalMass()
//
void ParticleSystem::updateAdditionalMass()
{
    for (unsigned i = 0; i < 12; i++)
    {
        particleArray[i].setMass(BASE_MASS);
    } // for

    // Find the coordinates of the mass as an index and proportion
    int x = int(massPos.x);
    real xp = real_fmod(massPos.x, cyclone::real(1.0f));
    if (x < 0)
    {
        x = 0;
        xp = 0;
    } // if
    if (x >= 5)
    {
        x = 5;
        xp = 0;
    } // if

    int z = int(massPos.z);
    real zp = real_fmod(massPos.z, real(1.0f));
    if (z < 0)
    {
        z = 0;
        zp = 0;
    } // if
    if (z >= 1)
    {
        z = 1;
        zp = 0;
    } // if

    // Calculate where to draw the mass
    massDisplayPos.clear();

    // Add the proportion to the correct masses
    particleArray[x*2+z].setMass(BASE_MASS + EXTRA_MASS*(1-xp)*(1-zp));
    massDisplayPos.addScaledVector(
        particleArray[x*2+z].getPosition(), (1-xp)*(1-zp)
        );

    if (xp > 0)
    {
        particleArray[x*2+z+2].setMass(BASE_MASS + EXTRA_MASS*xp*(1-zp));
        massDisplayPos.addScaledVector(
            particleArray[x*2+z+2].getPosition(), xp*(1-zp)
            );

        if (zp > 0)
        {
            particleArray[x*2+z+3].setMass(BASE_MASS + EXTRA_MASS*xp*zp);
            massDisplayPos.addScaledVector(
                particleArray[x*2+z+3].getPosition(), xp*zp
                );
        }   // if
    } // if
    if (zp > 0)
    {
        particleArray[x*2+z+1].setMass(BASE_MASS + EXTRA_MASS*(1-xp)*zp);
        massDisplayPos.addScaledVector(
            particleArray[x*2+z+1].getPosition(), (1-xp)*zp
            );
    } // if
}  // ParticleSystem::updateAdditionalMass()


//
//ParticleSystem::~ParticleSystem
//destructor
ParticleSystem::~ParticleSystem(void)
{
}

//
//ParticleSystem::display
//draws the particles and handles what happens when they pass
//through a portal
void ParticleSystem::display(Vector3 portEntry, Vector3 portExit)
{
    Particle **particles;        //pointers for particles
    glBegin(GL_LINES);
    glLineWidth(5);              //give the rod a width
    glColor3f(0,0,1);            //color the rods blue
    Vector3 &p1 = Vector3();     //position of particle
    Vector3 &p0 = Vector3();     //    "     "     "
    
    //Handle how the rod passes through the portal
    for (unsigned i = 0; i < 1; i++)
    {
       //get positions of particles
        particles = rods[i].particle;
        p1 = particles[1]->getPosition();
        p0 = particles[0]->getPosition();

        //if both particles haven't crossed a portal yet, connect them as normal
        if(p0.z > portEntry.z && p1.z > portEntry.z)
        {
            glVertex3f((float)p0.x, (float)p0.y, (float)p0.z);
            glVertex3f((float)p1.x, (float)p1.y, (float)p1.z);
        }   // if

        //else if one particle has passed through, make the illusion that the rod
        //is being translated by having them connect through the portal
        else if(p0.z < portEntry.z && p1.z < portEntry.z)
        {
           glVertex3f((float)p0.x - Vector3(portEntry - portExit).x,
                       (float)p0.y - Vector3(portEntry - portExit).y,
                       (float)p0.z - Vector3(portEntry - portExit).z);

           glVertex3f((float)p1.x - Vector3(portEntry - portExit).x,
                       (float)p1.y - Vector3(portEntry - portExit).y,
                       (float)p1.z - Vector3(portEntry - portExit).z);
        }   // else if

        //else the rod is through the portal and advance it
        //as normal
        else
        {
            glVertex3f((float)p1.x, (float)p1.y, (float)p1.z);
            glVertex3f(portEntry.x, portEntry.y, portEntry.z);
           
            glVertex3f((float)p0.x - Vector3(portEntry - portExit).x,
                       (float)p0.y - Vector3(portEntry - portExit).y,
                       (float)p0.z - Vector3(portEntry - portExit).z);
            glVertex3f(portExit.x, portExit.y, portExit.z);
        }   // else
    }
    glEnd();

    glColor3f(1,0,0);      //color particles red

    glPushMatrix();
    
    //Handle how the particle moves if it hasn't passed through the portal yet
    if(p1.z > portEntry.z)
    {
       //translate the particle and draw it
      glTranslatef(particleArray[1].getPosition().x,
                   particleArray[1].getPosition().y,
                   particleArray[1].getPosition().z);
      glutSolidSphere(RADIUS, 20, 10);
    } // if
    //else handle after it moves through portal
    else
    {
       //translate the particle and draw it
      glTranslatef(particleArray[1].getPosition().x - Vector3(portEntry - portExit).x,
                   particleArray[1].getPosition().y - Vector3(portEntry - portExit).y,
                   particleArray[1].getPosition().z - Vector3(portEntry - portExit).z);
      glutSolidSphere(RADIUS, 20, 10);
    }
    glPopMatrix();
   
    //Handle how the particle moves if it hasn't passed through the portal yet
    if(p0.z > portEntry.z)
    {
       //translate the particle and draw it
      glTranslatef(particleArray[0].getPosition().x,
                   particleArray[0].getPosition().y,
                   particleArray[0].getPosition().z);
      glutSolidSphere(RADIUS, 20, 10);
    } // if
    //else handle after it moves through portal
    else
    {
      glTranslatef(particleArray[0].getPosition().x - Vector3(portEntry - portExit).x,
                   particleArray[0].getPosition().y - Vector3(portEntry - portExit).y,
                   particleArray[0].getPosition().z - Vector3(portEntry - portExit).z);
      glutSolidSphere(RADIUS, 20, 10);
    } // else
    glPopMatrix();
}  // ParticleSystem::display()

//
//ParticleSystem::getRadius()
//return the radius of the particle
float ParticleSystem::getRadius()
{
   return RADIUS;

}  // ParticleSystem::getRadius()

//
//ParticleSystem::getPosition
//return the position of a particle in Vector3 coordinates
Vector3 ParticleSystem::getPosition(int i)
{ 
   // if i is 2, return the midpoint
   if(i==2)
   {
      Vector3 midPoint;
      midPoint.x = particleArray[0].getPosition().x+((particleArray[0].getPosition().x-particleArray[1].getPosition().x)/2);
      midPoint.y = particleArray[0].getPosition().y+((particleArray[0].getPosition().y-particleArray[1].getPosition().y)/2);
      midPoint.z = particleArray[0].getPosition().z+((particleArray[0].getPosition().z-particleArray[1].getPosition().z)/2);
      return midPoint;
   }
   return particleArray[i].getPosition();

}  // ParticleSystem::getPosition